﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Distributed;
using Newtonsoft.Json;

namespace Infrastructure.Cache
{
    /// <summary>
    /// 分布式缓存管理器：提供对 IDistributedCache 的扩展封装，支持对象序列化/反序列化和基础缓存操作
    /// </summary>
    public class DistributedCacheManager
    {
        // 依赖注入的分布式缓存实例（如 Redis、SQL Server 等实现）
        protected IDistributedCache cache;

        /// <summary>
        /// 构造函数：通过依赖注入获取 IDistributedCache 实例
        /// </summary>
        /// <param name="cache">具体的分布式缓存实现</param>
        public DistributedCacheManager(IDistributedCache cache)
        {
            this.cache = cache;
        }

        /// <summary>
        /// 设置缓存项（带过期策略）
        /// </summary>
        /// <param name="key">缓存键</param>
        /// <param name="value">缓存值（任意对象）</param>
        /// <param name="distributedCacheEntryOptions">缓存过期策略配置</param>
        public void Set(string key, object value, DistributedCacheEntryOptions distributedCacheEntryOptions)
        {
            // 序列化对象为 JSON 字符串（处理循环引用，保留类型信息）
            string s = JsonConvert.SerializeObject(value, new JsonSerializerSettings
            {
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore, // 忽略循环引用
                TypeNameHandling = TypeNameHandling.All                // 保留类型信息（反序列化时需要）
            });

            // 转换为字节数组存储
            byte[] bytes = Encoding.UTF8.GetBytes(s);

            // 存储到缓存
            cache.Set(key, bytes, distributedCacheEntryOptions);

            // 刷新缓存项的过期时间（针对滑动过期策略）
            Refresh(key);
        }

        /// <summary>
        /// 检查缓存项是否存在
        /// </summary>
        /// <param name="key">缓存键</param>
        /// <returns>存在返回 true</returns>
        public bool Exist(string key)
        {
            byte[] array = cache.Get(key);
            return array != null; // 空值判断（注意：某些实现可能返回空数组而非 null）
        }

        /// <summary>
        /// 获取缓存项（泛型方法）
        /// </summary>
        /// <typeparam name="T">目标数据类型</typeparam>
        /// <param name="key">缓存键</param>
        /// <param name="isExisted">输出参数：指示缓存项是否存在</param>
        /// <returns>存在时返回反序列化对象，否则返回默认值</returns>
        public T Get<T>(string key, out bool isExisted)
        {
            byte[] array = cache.Get(key);
            if (array == null)
            {
                isExisted = false;
                return default(T);
            }

            // 反序列化 JSON 字符串为对象（需与序列化时的 TypeNameHandling 设置匹配）
            string @string = Encoding.UTF8.GetString(array);
            isExisted = true;
            return JsonConvert.DeserializeObject<T>(@string, new JsonSerializerSettings
            {
                TypeNameHandling = TypeNameHandling.All // 根据类型信息反序列化
            });
        }

        /// <summary>
        /// 移除缓存项
        /// </summary>
        /// <param name="key">缓存键</param>
        public void Remove(string key)
        {
            cache.Remove(key);
        }

        /// <summary>
        /// 刷新缓存项（重置滑动过期时间）
        /// </summary>
        /// <param name="key">缓存键</param>
        public void Refresh(string key)
        {
            cache.Refresh(key); // 仅对配置了滑动过期的缓存项有效
        }
    }
}
